﻿#region Using

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Vk.Methods.Common;
using Vk.Methods.Groups;
using Vk.Methods.Users;

#endregion

namespace Vk.Methods.Wall
{
    /// <summary>
    ///     Стена
    /// </summary>
    public class Wall
    {
        private readonly Api _api;

        public Wall(Api api)
        {
            _api = api;
        }

        /// <summary>
        ///     Добавляет комментарий к записи на стене пользователя.
        /// </summary>
        /// <param name="postId">Идентификатор записи на стене пользователя.</param>
        /// <param name="message">Текст комментария к записи на стене пользователя.</param>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, на чьей стене находится запись к которой необходимо добавить
        ///     комментарий. Если параметр не задан, то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="replyToComment">Идентификатор комментария, ответом на который является добавляемый комментарий.</param>
        /// <param name="attachments">Список объектов, приложенных к комментарию и разделённых символом ",".</param>
        /// <param name="fromGroup">
        ///     Данный параметр учитывается, если owner_id менее 0 (комментарий публикуется на стене группы).
        ///     true — комментарий будет опубликован от имени группы, false — комментарий будет опубликован от имени пользователя
        ///     (по умолчанию).
        /// </param>
        /// <param name="stickerId">Идентификатор стикера.</param>
        /// <param name="guid">
        ///     Уникальный идентификатор, предназначенный для предотвращения повторной отправки одинакового
        ///     комментария.
        /// </param>
        /// <returns>
        ///     В случае успешного добавления комментария к записи возвращает идентификатор добавленного комментария на стене
        ///     пользователя.
        /// </returns>
        public async Task<int> CreateComment(int postId,
                                             string message,
                                             int? ownerId = null,
                                             int? replyToComment = null,
                                             IEnumerable<string> attachments = null,
                                             bool? fromGroup = null,
                                             int? stickerId = null,
                                             string guid = null)
        {
            if (message == null && attachments == null)
            {
                throw new ArgumentException("At least on of the parameters must be not null: message, attachments");
            }

            var query = new ApiQuery("wall.createComment")
                .Add("post_id", postId)
                .Add("owner_id", ownerId)
                .Add("message", message)
                .Add("from_group", fromGroup)
                .Add("reply_to_comment", replyToComment)
                .Add("attachments", attachments)
                .Add("sticker_id", stickerId)
                .Add("guid", guid);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Int().HasValue
                       ? result.Int().Value
                       : -1;
        }

        /// <summary>
        ///     Удаляет запись со стены пользователя.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, на чьей стене необходимо удалить запись. Если параметр не задан, то
        ///     он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="postId">Идентификатор записи на стене пользователя.</param>
        /// <returns>В случае успешного удаления записи со стены пользователя возвращает true. </returns>
        public async Task<bool> Delete(int postId, int? ownerId = null)
        {
            var query = new ApiQuery("wall.delete")
                .Add("owner_id", ownerId)
                .Add("post_id", postId);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                if (!result.ChildNodes.Any())
                {
                    return false;
                }

                return result.String().Equals("1");
            }
            return false;
        }

        /// <summary>
        ///     Удаляет комментарий текущего пользователя к записи на своей или чужой стене.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, на чьей стене находится комментарий к записи. Если параметр не задан,
        ///     то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="commentId">Идентификатор комментария на стене пользователя.</param>
        /// <returns>В случае успеха возвращает true. </returns>
        public async Task<bool> DeleteComment(int commentId, int? ownerId)
        {
            var query = new ApiQuery("wall.deleteComment")
                .Add("owner_id", ownerId)
                .Add("comment_id", commentId);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return result.Bool().Value;
            }
            return false;
        }

        /// <summary>
        ///     Редактирует запись на своей или чужой стене.
        /// </summary>
        /// <param name="postId">Идентификатор записи на стене пользователя.</param>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, на чьей стене находится запись, которую необходимо отредактировать.
        ///     Если параметр не задан, то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="message">Текст сообщения (является обязательным, если не задан параметр attachments)</param>
        /// <param name="attachments">Список объектов, приложенных к записи и разделённых символом ",". </param>
        /// <param name="lat">Географическая широта отметки, заданная в градусах (от -90 до 90).</param>
        /// <param name="long">Географическая долгота отметки, заданная в градусах (от -180 до 180).</param>
        /// <param name="placeId">Идентификатор места, в котором отмечен пользователь</param>
        /// <param name="friendsOnly">
        ///     true — запись будет доступна только друзьям, false — всем пользователям. Параметр учитывается
        ///     только при редактировании отложенной записи.
        /// </param>
        /// <param name="publishDate">
        ///     Дата публикации записи в формате unixtime. Если параметр не указан, отложенная запись будет
        ///     опубликована. Параметр учитывается только при редактировании отложенной записи.
        /// </param>
        /// <param name="services">
        ///     Список сервисов или сайтов, на которые необходимо экспортировать запись, в случае если
        ///     пользователь настроил соответствующую опцию. Например, twitter, facebook. Параметр учитывается только при
        ///     редактировании отложенной записи.
        /// </param>
        /// <param name="signed">
        ///     true — у записи, размещенной от имени сообщества будет добавлена подпись (имя пользователя,
        ///     разместившего запись), false — подписи добавлено не будет. Параметр учитывается только при редактировании записи на
        ///     стене сообщества, опубликованной от имени группы.
        /// </param>
        /// <returns>В случае успешного сохранения записи метод возвратит true. </returns>
        public async Task<bool> Edit(int postId,
                                     int? ownerId,
                                     string message,
                                     IEnumerable<string> attachments,
                                     short? lat,
                                     short? @long,
                                     int? placeId,
                                     bool? friendsOnly = null,
                                     string services = null,
                                     int? publishDate = null,
                                     bool? signed = null,
                                     bool? markAsAds = null)
        {
            if (message == null && attachments == null)
                throw new ArgumentNullException("message" + " & " + "attachments");
            var query = new ApiQuery("wall.post")
                .Add("owner_id", ownerId) //((type == MessageType.Outgoing) ? "1" : "0"));
                .Add("attachments", attachments)
                .Add("lat", lat)
                .Add("long", @long)
                .Add("place_id", placeId)
                .Add("services", services)
                .Add("friends_only", friendsOnly)
                .Add("publish_date", publishDate)
                .Add("signed", signed)
                .Add("post_id", postId)
                .Add("mark_as_ads", markAsAds)
                .Add("message", message);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                if (!result.ChildNodes.Any())
                {
                    return false;
                }

                return result.String().Equals("1");
            }
            return false;
        }

        /// <summary>
        ///     Редактирует комментарий на стене пользователя или сообщества.
        /// </summary>
        /// <param name="commentId">Идентификатор комментария, который необходимо отредактировать.</param>
        /// <param name="ownerId">Идентификатор владельца стены. </param>
        /// <param name="message">Новый текст комментария.</param>
        /// <param name="attachments">Новые вложения к комментарию. </param>
        /// <returns>После успешного выполнения возвращает true.</returns>
        public async Task<bool> EditComment(int commentId,
                                            int? ownerId = null,
                                            string message = null,
                                            IEnumerable<string> attachments = null)
        {
            var query = new ApiQuery("wall.addComment")
                .Add("owner_id", ownerId)
                .Add("comment_id", commentId)
                .Add("message", message)
                .Add("attachments", attachments);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return result.Bool().Value;
            }
            return false;
        }

        /// <summary>
        ///     Возвращает список записей со стены пользователя или сообщества.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор пользователя (по умолчанию - текущий пользователь). Чтобы получить записи со стены
        ///     группы (публичной страницы, встречи), укажите её идентификатор со знаком "минус": например, owner_id=-1
        ///     соответствует группе с идентификатором 1.
        /// </param>
        /// <param name="domain">Короткий адрес пользователя или сообщества.</param>
        /// <param name="count">Количество сообщений, которое необходимо получить (но не более 100).</param>
        /// <param name="offset">Смещение, необходимое для выборки определенного подмножества сообщений.</param>
        /// <param name="filter">Определяет, какие типы сообщений на стене необходимо получить.</param>
        /// <param name="extended">
        ///     true — в ответе будут возвращены дополнительные поля profiles и groups, содержащие информацию о
        ///     пользователях и сообществах. По умолчанию: false.
        /// </param>
        /// <param name="fields">Cписок дополнительных полей для профилей и групп, которые необходимо вернуть. </param>
        public async Task<ItemsCountProfilesGroups<WallPost>> Get(int? ownerId = null,
                                                                    string domain = null,
                                                                    int? count = null,
                                                                    int? offset = null,
                                                                    WallEntityFilter filter = null,
                                                                    bool? extended = null,
                                                                    IEnumerable<string> fields = null)
        {
            var query = new ApiQuery("wall.get", true)
                .Add("owner_id", ownerId)
                .Add("offset", offset)
                .Add("count", count)
                .Add("filter", filter.StringValue)
                .Add("domain", domain)
                .Add("extended", extended)
                .Add("fields", fields);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return new ItemsCountProfilesGroups<WallPost>(result, node => new WallPost(node));
            }
            return null;
        }

        /// <summary>
        ///     Возвращает список записей со стен пользователей по их идентификаторам.
        /// </summary>
        /// <param name="posts">
        ///     Перечисленные через запятую идентификаторы, которые представляют собой идущие через знак
        ///     подчеркивания id владельцев стен и id самих записей на стене.
        /// </param>
        /// <param name="copyHistoryDepth">
        ///     определяет размер массива copy_history, возвращаемого в ответе, если запись является репостом записи с другой
        ///     стены.
        ///     Например, copy_history_depth=1 — copy_history будет содержать один элемент с информацией о записи, прямым репостом
        ///     которой является текущая.
        ///     copy_history_depth=2 — copy_history будет содержать два элемента, добавляется информация о записи, репостом которой
        ///     является первый элемент, и так далее
        ///     (при условии, что иерархия репостов требуемой глубины для текущей записи существует).
        /// </param>
        /// <param name="extended">
        ///     true — в ответе будут возвращены дополнительные поля profiles и groups, содержащие информацию о
        ///     пользователях и сообществах. По умолчанию: false.
        /// </param>
        /// <param name="fields">Cписок дополнительных полей для профилей и групп, которые необходимо вернуть. </param>
        /// <seealso cref="UserFields" />
        /// <seealso cref="GroupFields" />
        public async Task<List<WallPost>> GetById(IEnumerable<string> posts,
                                                    short? copyHistoryDepth = null,
                                                    bool? extended = null,
                                                    IEnumerable<string> fields = null)
        {
            var query = new ApiQuery("wall.getById", true)
                .Add("posts", posts)
                .Add("copy_history_depth", copyHistoryDepth)
                .Add("extended", extended)
                .Add("fields", fields);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed
                       ? result.SelectNodes("post").Select(y => new WallPost(y)).ToList()
                       : null;
        }

        /// <summary>
        ///     Возвращает список комментариев к записи на стене пользователя.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, на чьей стене находится запись, к которой необходимо получить
        ///     комментарии. Если параметр не задан, то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="postId">Идентификатор записи на стене пользователя.</param>
        /// <param name="sort">Порядок сортировки комментариев</param>
        /// <param name="extended">
        ///     true — в ответе будут возвращены дополнительные поля profiles и groups, содержащие информацию о
        ///     пользователях и сообществах. По умолчанию: 0.
        /// </param>
        /// <param name="offset">Смещение, необходимое для выборки определенного подмножества комментариев.</param>
        /// <param name="count">Количество комментариев, которое необходимо получить (но не более 100).</param>
        /// <param name="needLikes">1 - будет возвращено дополнительное поле likes. По умолчанию поле likes не возвращается.</param>
        /// <param name="previewLength">
        ///     Количество символов, по которому нужно обрезать комментарии. Укажите 0, если Вы не хотите
        ///     обрезать комментарии. (по умолчанию 90). Обратите внимание, что комментарии обрезаются по словам.
        /// </param>
        /// <param name="startCommentId">Идентификатор комментария, начиная с которого нужно вернуть список</param>
        public async Task<ItemsCountProfilesGroups<Comment>> GetComments(int postId,
                                                                         int? ownerId = null,
                                                                         SortOrder sort = null,
                                                                         bool? extended = null,
                                                                         int? offset = null,
                                                                         int? count = null,
                                                                         bool? needLikes = null,
                                                                         int? previewLength = null,
                                                                         int? startCommentId = null)
        {
            var query = new ApiQuery("wall.getComments", true)
                .Add("owner_id", ownerId)
                .Add("post_id", postId)
                .Add("sort", sort.StringValue)
                .Add("offset", offset)
                .Add("count", count)
                .Add("need_likes", needLikes)
                .Add("preview_length", previewLength)
                .Add("start_comment_id", startCommentId)
                .Add("extended", extended);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return new ItemsCountProfilesGroups<Comment>(result, node => new Comment(node));
            }
            return null;
        }

        /// <summary>
        ///     Позволяет получать список репостов заданной записи.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор пользователя или сообщества, на стене которого находится запись. Если параметр не
        ///     задан, то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="postId">Идентификатор записи на стене.</param>
        /// <param name="count">Количество записей, которое необходимо получить. </param>
        /// <param name="offset">Смещение, необходимое для выборки определенного подмножества записей. </param>
        public async Task<List<WallPost>> GetReposts(int? ownerId = null,
                                                       int? postId = null,
                                                       int? count = null,
                                                       int? offset = null)
        {
            var query = new ApiQuery("wall.getReposts", true)
                .Add("owner_id", ownerId)
                .Add("offset", offset)
                .Add("count", count)
                .Add("post_id", postId);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                if (!result.ChildNodes.Any())
                {
                    return null;
                }

                return new List<WallPost>(result.SelectNodes("//items/item").Select(y => new WallPost(y)).ToList());
            }
            return null;
        }

        /// <summary>
        ///     Закрепляет запись на стене (запись будет отображаться выше остальных).
        /// </summary>
        /// <param name="postId">Идентификатор записи на стене. </param>
        /// <param name="ownerId">Идентификатор пользователя или сообщества, на стене которого находится запись.</param>
        /// <returns>После успешного выполнения возвращает true.</returns>
        public async Task<bool> Pin(int postId, int? ownerId = null)
        {
            var query = new ApiQuery("wall.pin")
                .Add("post_id", postId)
                .Add("owner_id", ownerId);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Публикует новую запись на своей или чужой стене.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, у которого должна быть опубликована запись. Если параметр не задан,
        ///     то считается, что он равен идентификатору текущего пользователя.
        /// </param>
        /// <param name="message">Текст сообщения (является обязательным, если не задан параметр attachments)</param>
        /// <param name="attachments">Cписок объектов, приложенных к записи и разделённых символом ",".</param>
        /// <param name="lat">Географическая широта отметки, заданная в градусах (от -90 до 90).</param>
        /// <param name="long">Географическая долгота отметки, заданная в градусах (от -180 до 180).</param>
        /// <param name="placeId">Идентификатор места, в котором отмечен пользователь</param>
        /// <param name="fromGroup">
        ///     Данный параметр учитывается, если owner_id меньше 0 (статус публикуется на стене группы). 1 -
        ///     статус будет опубликован от имени группы, 0 - статус будет опубликован от имени пользователя (по умолчанию).
        /// </param>
        /// <param name="services">
        ///     Список сервисов или сайтов, на которые необходимо экспортировать запись, в случае если
        ///     пользователь настроил соответствующую опцию. Например, twitter, facebook.
        /// </param>
        /// <param name="postId">
        ///     Идентификатор записи, которую необходимо опубликовать. Данный параметр используется для публикации
        ///     отложенных записей и предложенных новостей.
        /// </param>
        /// <param name="publishDate">
        ///     Дата публикации записи в формате unixtime. Если параметр указан, публикация записи будет
        ///     отложена до указанного времени.
        /// </param>
        /// <param name="signed">
        ///     1 - у статуса, размещенного от имени группы будет добавлена подпись (имя пользователя,
        ///     разместившего запись), 0 - подписи добавлено не будет. Параметр учитывается только при публикации на стене группы и
        ///     указании параметра from_group. По умолчанию подпись не добавляется.
        /// </param>
        /// <param name="friendsOnly">
        ///     1 - статус будет доступен только друзьям, 0 - всем пользователям. По умолчанию публикуемые
        ///     статусы доступны всем пользователям.
        /// </param>
        /// <param name="guid">Уникальный идентификатор, предназначенный для предотвращения повторной отправки одинаковой записи. </param>
        /// <returns>В случае успеха возвращает идентификатор созданной записи. </returns>
        public async Task<int> Post(int? ownerId,
                                    string message,
                                    int? publishDate = null,
                                    int? postId = null,
                                    int? placeId = null,
                                    IEnumerable<WallAttachment> attachments = null,
                                    short? lat = null,
                                    short? @long = null,
                                    bool? fromGroup = null,
                                    bool? signed = null,
                                    bool? friendsOnly = null,
                                    string services = null,
                                    string guid = null,
                                    bool? markAsAds = null)
        {
            if (message == null && attachments == null)
                throw new ArgumentException("Message and attachments can't be null simultaneously");
            var query = new ApiQuery("wall.post")
                .Add("owner_id", ownerId)
                .Add("post_id", postId)
                .Add("place_id", placeId)
                .Add("attachments", attachments)
                .Add("services", services)
                .Add("publish_date", publishDate)
                .Add("lat", lat)
                .Add("long", @long)
                .Add("from_group", fromGroup)
                .Add("signed", signed)
                .Add("friends_only", friendsOnly)
                .Add("message", message)
                .Add("mark_as_ads", markAsAds)
                .Add("guid", guid);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Int("post_id").HasValue ? result.Int("post_id").Value : -1;
        }

        /// <summary>
        ///     Позволяет пожаловаться на запись.
        /// </summary>
        /// <param name="commentId">Идентификатор комментария. </param>
        /// <param name="ownerId">Идентификатор пользователя или сообщества, которому принадлежит комментарий. </param>
        /// <param name="reason">Тип жалобы</param>
        /// <returns>После успешного выполнения возвращает true.</returns>
        public async Task<bool> ReportComment(int commentId, int ownerId, ReportReason reason = null)
        {
            var query = new ApiQuery("wall.reportComment")
                .Add("owner_id", ownerId)
                .Add("comment_id", commentId)
                .Add("reason", reason.Value);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return result.Bool().Value;
            }
            return false;
        }

        /// <summary>
        ///     Позволяет пожаловаться на запись.
        /// </summary>
        /// <param name="postId">Идентификатор записи. </param>
        /// <param name="ownerId">Идентификатор пользователя или сообщества, которому принадлежит запись. </param>
        /// <param name="reason">Тип жалобы</param>
        /// <returns>После успешного выполнения возвращает true.</returns>
        public async Task<bool> ReportPost(int postId, int ownerId, ReportReason reason = null)
        {
            var query = new ApiQuery("wall.reportPost")
                .Add("owner_id", ownerId)
                .Add("post_id", postId)
                .Add("reason", reason.Value);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Копирует объект на стену пользователя или сообщества.
        /// </summary>
        /// <param name="object">
        ///     Строковый идентификатор объекта, который необходимо разместить на стене, например, wall66748_3675 или
        ///     wall-1_340364.
        /// </param>
        /// <param name="message">Сопроводительный текст, который будет добавлен к записи с объектом.</param>
        /// <param name="groupId">
        ///     Идентификатор сообщества, на стене которого будет размещена запись с объектом. Если не указан,
        ///     запись будет размещена на стене текущего пользователя.
        /// </param>
        public async Task<RepostSuccess> Repost(string @object, string message = null, int? groupId = null)
        {
            var query = new ApiQuery("wall.repost")
                .Add("object", @object)
                .Add("message", message)
                .Add("group_id", groupId);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                if (!result.ChildNodes.Any())
                {
                    return null;
                }

                return new RepostSuccess(result);
            }
            return null;
        }

        /// <summary>
        ///     Восстанавливает удаленную запись на стене пользователя.
        /// </summary>
        /// <param name="postId">Идентификатор записи на стене пользователя.</param>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, на чьей стене необходимо восстановить запись. Если параметр не задан,
        ///     то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <returns></returns>
        public async Task<bool> Restore(int postId, int? ownerId = null)
        {
            var query = new ApiQuery("wall.restore")
                .Add("owner_id", ownerId)
                .Add("post_id", postId);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                if (!result.ChildNodes.Any())
                {
                    return false;
                }

                return result.String().Equals("1");
            }
            return false;
        }

        /// <summary>
        ///     Восстанавливает комментарий текущего пользователя к записи на своей или чужой стене.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор пользователя, на чьей стене находится комментарий к записи. Если параметр не задан,
        ///     то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="commentId">Идентификатор комментария на стене пользователя.</param>
        /// <returns>В случае успеха возвращает true. </returns>
        public async Task<bool> RestoreComment(int commentId, int? ownerId)
        {
            var query = new ApiQuery("wall.restoreComment")
                .Add("owner_id", ownerId)
                .Add("comment_id", commentId);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return result.Bool().Value;
            }
            return false;
        }

        /// <summary>
        ///     Метод позволяющий осуществлять поиск по стенам пользователей.
        /// </summary>
        /// <param name="query">Поисковой запрос.</param>
        /// <param name="ownerId">Идентификатор пользователя или сообщества. </param>
        /// <param name="domain">Короткий адрес пользователя или сообщества. </param>
        /// <param name="ownersOnly">true — возвращать только записи от имени владельца стены. </param>
        /// <param name="count">Количество записей, которые необходимо вернуть. </param>
        /// <param name="offset">Смещение. </param>
        /// <param name="extended">Возвращать ли расширенную информацию о записях. </param>
        /// <param name="fields">Список дополнительных полей для профилей и групп, которые необходимо вернуть.</param>
        /// <seealso cref="UserFields" />
        /// <seealso cref="GroupFields" />
        public async Task<ItemsCountProfilesGroups<WallPost>> Search(string query,
                                                                       int? ownerId = null,
                                                                       string domain = null,
                                                                       bool? ownersOnly = null,
                                                                       int? count = null,
                                                                       int? offset = null,
                                                                       bool? extended = null,
                                                                       IEnumerable<string> fields = null)
        {
            var apiQuery = new ApiQuery("wall.search", true)
                .Add("query", query)
                .Add("owner_id", ownerId)
                .Add("offset", offset)
                .Add("count", count)
                .Add("domain", domain)
                .Add("owners_only", ownersOnly)
                .Add("extended", extended)
                .Add("fields", fields);

            var result = await _api.Manager.Execute(apiQuery);
            return _api.Manager.MethodSuccessed
                       ? new ItemsCountProfilesGroups<WallPost>(result, node => new WallPost(node))
                       : null;
        }

        /// <summary>
        ///     Отменяет закрепление записи на стене.
        /// </summary>
        /// <param name="postId">Идентификатор записи на стене. </param>
        /// <param name="ownerId">Идентификатор пользователя или сообщества, на стене которого находится запись.</param>
        /// <returns>После успешного выполнения возвращает true.</returns>
        public async Task<bool> Unpin(int postId, int? ownerId = null)
        {
            var query = new ApiQuery("wall.unpin")
                .Add("post_id", postId)
                .Add("owner_id", ownerId);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }
    }
}